﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using BeatlesBlog.SimConnect;
using FA.Plugins.FSXPlugin.Sim;
using FA.Library.Sim;
using FA.Plugins.FSXPlugin.Sim.Aircraft;
using FA.Library.Sim.Aircraft;

namespace FA.Plugins.FSXPlugin.Sim
{
    /// <summary>
    /// This class is responsible for interacting with the flight sim
    /// application via the SimConnect object.
    /// </summary>
    public class SimController : IDisposable
    {
        public event Action Connected;
        public event Action Disposed;
        public event Action AircraftModelUpdated;

        /// <summary>
        /// The aircraft model.
        /// </summary>
        public AircraftModel AircraftModel
        {
            get { return _aircraftModel; }
            private set
            {
                if (value != _aircraftModel)
                {
                    _aircraftModel = value;
                    if (AircraftModelUpdated != null)
                        AircraftModelUpdated();
                }
            }
        }
        private AircraftModel _aircraftModel;

        /// <summary>
        /// SimConnect object.
        /// </summary>
        private SimConnect _simConnect;

        // These three properties should only be set in the constructor
        public string Name { get; private set; }
        public string Host { get; private set; }
        public int Port { get; private set; }

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="handle"></param>
        /// <param name="simID"></param>
        public SimController(string name, string host, int port)
        {
            Name = name;
            Host = host;
            Port = port;

            _simConnect = new SimConnect(null);

            initEventHandlers();
        }

        /// <summary>
        /// Run the sim controller.
        /// </summary>
        public void Run()
        {
            if (SimConnect.IsLocalRunning())
            {
                _simConnect.Open(Name, Host, Port);
            }
            else
            {
                throw new Exception("FSX is not currently running.");
            }
        }

        /// <summary>
        /// Dispose the controller.
        /// </summary>
        public void Dispose()
        {
            if (_simConnect != null)
            {
                _simConnect.Close();
                _simConnect = null;
            }

            if (Disposed != null)
                Disposed();
        }

        /// <summary>
        /// Register the event handlers.
        /// </summary>
        private void initEventHandlers()
        {
            _simConnect.OnRecvOpen += new SimConnect.RecvOpenEventHandler(simConnect_OnRecvOpen);
            _simConnect.OnRecvQuit += new SimConnect.RecvQuitEventHandler(simConnect_OnRecvQuit);
            _simConnect.OnRecvSimobjectData += new SimConnect.RecvSimobjectDataEventHandler(simConnect_OnRecvSimobjectData);
        }

        /// <summary>
        /// Connection to SimConnect is opened.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="data"></param>
        private void simConnect_OnRecvOpen(SimConnect sender, SIMCONNECT_RECV_OPEN data)
        {
            if (Connected != null)
                Connected();

            // Request periodic information on the user's aircraft information
            sender.RequestDataOnUserSimObject(
                SimRequest.UserAircraftInfo,
                SIMCONNECT_PERIOD.SIM_FRAME,
                SIMCONNECT_DATA_REQUEST_FLAG.CHANGED,
                typeof(FSXAircraftModel));
        }
        
        /// <summary>
        /// User has quit the simulator application.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="data"></param>
        private void simConnect_OnRecvQuit(SimConnect sender, SIMCONNECT_RECV data)
        {
            // Dispose the controller
            Dispose();
        }

        /// <summary>
        /// Simulator object data received.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="data"></param>
        private void simConnect_OnRecvSimobjectData(SimConnect sender, SIMCONNECT_RECV_SIMOBJECT_DATA data)
        {
            SimRequest request = (SimRequest) data.dwRequestID;
            switch (request)
            {
                // Received the user's aircraft info
                case SimRequest.UserAircraftInfo:
                    FSXAircraftModel aircraftModel = (FSXAircraftModel)data.dwData;
                    aircraftModel.SetObjectID(data.dwObjectID);
                    if (aircraftModel.IsUser)
                        AircraftModel = aircraftModel;
                    break;
            }
        }

        /// <summary>
        /// Update the aircraft model for the plugin.
        /// </summary>
        /// <param name="model"></param>
        public void UpdateAircraftModel(AircraftModel model, bool supressEvent)
        {
            // TODO
            throw new NotImplementedException();
        }
    }
}
